package edu.umn.se.trap;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import databases.CurrencyDB;
import databases.GrantDB;
import databases.KeyNotFoundException;
import databases.PerDiemDB;
import databases.UserDB;
import databases.UserGrantDB;
import edu.umn.se.trap.exceptions.FormMemoryException;
import edu.umn.se.trap.exceptions.TrapException;
import edu.umn.se.trap.logicChecker.LogicChecker;

public class TravelFormProcessor implements TravelFormProcessorIntf
{
    private FormMemory formMemory;
    public TravelFormProcessor() {
        formMemory = new FormMemory();
    }
    public TravelFormProcessor(UserDB uDB,
            PerDiemDB perDiemDB,
            GrantDB grantDB,
            UserGrantDB userGrantDB,
            CurrencyDB currencyDB) {
        formMemory = new FormMemory();
    }
    
    /**
     * sets the username in the form memory
     * @param userId - the x500 username
     */
    public void setUser(String userId) throws Exception 
    {
        UserDB userdb = new UserDB();
        List<String> x500;
        try{
            x500 = userdb.getUserInfo(userId);
        }catch(KeyNotFoundException e){
            throw new TrapException("Invalid Key");
        }
        if(x500.get(0)==null)//if the username space isn't set
            throw new TrapException("Username not set");
        else 
        {
            User newUser = new User();
            newUser.username = x500.get(0);
            newUser.fullName = x500.get(1);
            newUser.email = x500.get(2);
            newUser.employeeId = x500.get(3);
            newUser.citizenship = x500.get(4);
            newUser.visaStatus = x500.get(5);
            newUser.paidByUniversity = x500.get(6);
        	formMemory.setUser(newUser);
        	
        }
    }
    
    /**
     * gets the current x500 username from memory
     * @return string - the x500 username
     */
    public String getUser(){
        String returner = formMemory.getUser().username;
        return returner;
    }
    
    /**
     * Goes through memory, grabbing each form in the list in memory and storing them
     * in a Map to be returned to the user
     * @return a map consisting of the list of form descriptions that have been saved
     */
    public Map<Integer, TravelFormMetadata> getSavedForms() throws Exception
    {
        Map<Integer, TravelFormMetadata> returner = new HashMap<Integer, TravelFormMetadata>();
        TravelFormMetadata form;
        
        for(int i=0;i<formMemory.getMemoryLength();i++)
        {
            form = formMemory.getForm(i);
            returner.put(i,  form);
        }
        
        return returner;
    }
    
    /**
     * clears the list of saved forms
     */
    public void clearSavedForms() throws Exception
    {
        //throws the exception inside the called function (if one is to be thrown)
        formMemory.clearForms();
    }
    
    /**
     * gets the saved map in data based upon the inputed form id
     * @param formId - the formId for the form that was saved in memory previously
     * @return a map of the form data previously stored
     */
    public Map<String, String> getSavedFormData(Integer formId) 
    throws Exception
    {
        //throws exception
        TravelFormMetadata temp;
        try
        {
            temp = formMemory.getForm(formId);
        }catch(FormMemoryException e)
        {
            throw new FormMemoryException("No previous form has been saved under formId " + formId.toString());
        }
        Map<String, String> returner = temp.getFormMap();
        return returner;
    }
    
    /**
     * saves a form in data 
     * @param formData - the data for the form
     * @param description - a string description for the form to be saved
     * @return the int position the form is stored at (formId)
     */
    public Integer saveFormData(Map<String, String> formData,
                                String description) 
            throws Exception
            {
        
        //adds a form in memory and returns the 'formId'
        //throws an exception inside addForm (if something fails)
        return formMemory.addForm(formData, description);
    }
    
    /**
     * saves a form in data 
     * @param formData - the data for the form
     * @param id - the previous location the form was stored at
     * @return the int position the form is re-stored at (formId)
     */
    public Integer saveFormData(Map<String, String> formData, 
            Integer id) 
            throws Exception
            {
        /*
         * gets the form - we do this because if the form doesn't exist
         * it throws an error in getForm
        */
        formMemory.getForm(id);
        
        formMemory.editForm(formData, id);
        return id;
    }
    
    /**
     * Submits the form data
     * gets the form map from memory, creates a form object, does the currency conversion,
     * checks the form for business logic and well-formedness, updates the grants,
     * and converts the output map
     */
    public void submitFormData(Integer formId) throws Exception
    {
        TravelFormMetadata formMap = formMemory.getForm(formId);
        //currency conversion is when the form is created
        Form form = FormFactory.createForm(formMap.getFormMap(), formMap.description);
        //instantiates the observable and observers
        LogicChecker formChecker = new LogicChecker();
        //notifies the observers (checkers)
        formChecker.checkForm(form);
        if(formChecker.getException()!=null)
        {
            throw formChecker.getException();
        }
        // try
        formMap.setFormMap(form.generateOutput());
        formMap.status = TravelFormProcessorIntf.FORM_STATUS.SUBMITTED;
        //catch
        
    }

    /**
     * gets the output form
     * @param formId - the integer representing where the form is stored in memory
     * @return Map<String, String> - the output form
     */
    public Map<String, String> getCompletedForm(Integer formId) throws Exception
    {
        TravelFormMetadata form = formMemory.getForm(formId);
        if(form.status!=TravelFormProcessorIntf.FORM_STATUS.SUBMITTED)
            throw new TrapException("Form under formId " + formId.toString() + " hasn't been completed yet");
        return form.getFormMap();
    }
}